Skip to content

Leetcode 321. Create Maximum Number

题目链接

Leetcode 321. Create Maximum Number

题目内容

Given two arrays of length m and n with digits 0-9 representing two numbers. Create the maximum number of length k <= m + n from digits of the two. The relative order of the digits from the same array must be preserved. Return an array of the k digits.

Note: You should try to optimize your time and space complexity.

Example1

Input: nums1 = [3, 4, 6, 5] nums2 = [9, 1, 2, 5, 8, 3] k = 5 Output: [9, 8, 6, 5, 3]

Example2

Input: nums1 = [6, 7] nums2 = [6, 0, 4] k = 5 Output: [6, 7, 6, 0, 4]

Example3

Input: nums1 = [3, 9] nums2 = [8, 9] k = 3 Output: [9, 8, 9]

解题思路

本周继续我们的DP之旅,本周的题同为hard但是比之之前的要复杂一些,老样子我们先找出我们的dp状态转移方程, dp[k] = MAX(merge(maxVector1[i], maxVector2[k-i]))

有了上面的状态转移方程之后,我们就可以知道,我们需要完成maxVector, merge以及一个比较函数了,maxVector用到了类似于贪心算法的思路

当vector的size大于我们所需要的size时,如果一个数字小于它后面的一个数,后一个数往前替代他必然会使数字更大,所以直接erase它

merge则类似于归并排序,这里不多说明

比较方面也比较简单,就是按位比较两个数字,并通过判断数字的长度决定大小关系

用这种方法得出的时间复杂度较高,提交detail为 detai

不太满意,后来经过思考发现maxVector其实很多操作是重复的,我们可以直接一次性算完单个vector对于每一种位数的max值,所以就有了第二种优化。

提交的detail为

detai

题目代码

一开始

class Solution {
public:
    vector<int> maxVector(vector<int> nums, int k) {
        while (nums.size() > k) {
            int i = 0, n = nums.size();
            for (; i < n - 1; ++i) {
                if (nums[i] < nums[i + 1]) {
                    nums.erase(nums.begin() + i);
                    break;
                }
            }
            if (i == n - 1) nums.erase(nums.begin() + i);
        }

        return nums;
    }

    bool compare(vector<int> &nums1, int i, vector<int> &nums2, int j) {
        while (i < nums1.size() && j < nums2.size() && nums1[i] == nums2[j]) {
            ++i;
            ++j;
        }
        if (j == nums2.size()) return true;
        if (i < nums1.size() && nums1[i] > nums2[j]) return true;
        return false;
    }

    vector<int> merge(vector<int> &nums1, vector<int> &nums2, int k) {
        vector<int> res(k, 0);
        for (int i = 0, j = 0, r = 0; r < k; ++r) {
            res[r] = compare(nums1, i, nums2, j) ? nums1[i++] : nums2[j++];
        }

        return res;
    }

    vector<int> maxNumber(vector<int>& nums1, vector<int>& nums2, int k) {
        int m = nums1.size(), n = nums2.size();
        vector<int> res(k, 0);

        for (int i = max(0, k - n); i <= min(k, m); ++i) {
            auto v1 = maxVector(nums1, i);
            auto v2 = maxVector(nums2, k - i);
            auto tmp = merge(v1, v2, k);
            if (compare(tmp, 0, res, 0)) res = tmp;
        }

        return res;
    }
};

优化

class Solution {
public:
    vector<int> maxNumber(vector<int>& nums1, vector<int>& nums2, int k) {
        vector<int> result;        
        vector<vector<int>> max1 (k+1), max2(k+1);

        getMax(nums1, max1, k);
        getMax(nums2, max2, k);

        for(int i = 0; i <= k; ++i){
            if(max1[i].size() + max2[k-i].size() < k){
                continue;
            }
            mergeMax(result, max1[i], max2[k-i], k);            
        }
        return result;
    }

    void getMax(vector<int>& nums, vector<vector<int>>& max, const int k){
        int start = 0, i = 0;
        while(nums.size() > 0){
            if(nums.size() <= k){
                max[nums.size()] = nums;
            }
            for(i = start; i + 1 < nums.size() && nums[i] >= nums[i+1]; ++i);
            nums.erase(nums.begin()+i);
            start = ((i == 0) ? 0 : i-1);
        }
    }

    void mergeMax(vector<int>& result, const vector<int>& max1, const vector<int>& max2, const int k){
        vector<int> temp (k,0);
        int i = 0, j = 0;
        for( ; i < max1.size() && j < max2.size(); ){
            int ii = i;
            int jj = j;
            while(ii < max1.size() && jj < max2.size()){
                if(max1[ii] == max2[jj]){
                    ++ii; ++jj;
                }
                else break;
            }
            if((ii < max1.size() && max1[ii] > max2[jj]) || jj >= max2.size()){
                temp[i+j] = max1[i];
                ++i;
            }
            else{
                temp[i+j] = max2[j];
                ++j;
            }
        }
        for( ; i < max1.size(); ++i){
            temp[i+j] = max1[i];
        }
        for( ; j < max2.size(); ++j){
            temp[i+j] = max2[j];
        }

        if(result.empty() || smaller(result, temp)){
            result = temp;
        }
    }

    bool smaller(const vector<int>& result, const vector<int>& temp){
        for(int i = 0; i < result.size(); ++i){
            if(result[i] < temp[i])
                return true;
            if(result[i] > temp[i])
                return false;
        }
        return false;
    }
};